///////////////////////////////////////////////////////////
///////////////// Have an itch? Scratch it! ///////////////
///////////////////////// SCRATCH /////////////////////////
/////////////////////  A MUD  Server   ////////////////////
///////////////////// By: Jared Devall ////////////////////
/////////////////////      Thanks:     ////////////////////
/////////////////////  DIKU/Merc/ROM   ////////////////////
///////////////////// Aetas/Deus Gang  ////////////////////
/////////////////////       Beej       ////////////////////
///////////////////////////////////////////////////////////

#include "definitions.h"
#include <list>
#include "commands.h"
#include "commandTable.h"
#include "character.h"
#include "world.h"
#include "stringutil.h"
#include "split.h"
#include "timestamp.h"
#include "vEditHandler.h"

using namespace std;

// rCommand definitions
// (Keep in alphabetical order... it's MUCH easier)

rCmdCommands::rCmdCommands( ) {
	SetName( "commands" );
	SetLevel( 1 );
	SetEnabled( true );
	SetOmniset( false );
}

bool rCmdCommands::Execute( Character* c, const string &args ) {
	std::string buf;
	std::string temp;
	list< Command* >::iterator it;
	int f = 0;

	if ( c->getLevel() >= HEAD ) {
		buf << "\n\r\t{chead (level " << HEAD << ") commands:{x\n\r";
		for ( it = rCommandTable::Instance()._commands.begin(); it != rCommandTable::Instance()._commands.end(); ++it ) {
			if ( (*it)->_level == HEAD ) {
				if ( !(*it)->_enabled )
					buf << "{w";
				if ( f == 0 ) {
					buf << "  " << (*it)->_name.c_str() << spaces( 12, (*it)->_name.c_str(), temp );
				} else {
					buf << (*it)->_name.c_str() << spaces( 12, (*it)->_name.c_str(), temp );
				}
				if ( !(*it)->_enabled )
					buf << "{x";
			    f++;
			    if ( f == 5 ) {
					buf << "\n\r";
					f = 0;
				}
			}
		}
	}
	f = 0;
	if ( c->getLevel() >= GOD ) {
		buf << "\n\r\t{cgod (level " << GOD << ") commands:{x\n\r";
		for ( it = rCommandTable::Instance()._commands.begin(); it != rCommandTable::Instance()._commands.end(); ++it ) {
			if ( (*it)->_level == GOD ) {
				if ( !(*it)->_enabled )
					buf << "{w";
				if ( f == 0 ) {
					buf << "  " << (*it)->_name.c_str() << spaces( 12, (*it)->_name.c_str(), temp );
				} else {
					buf << (*it)->_name.c_str() << spaces( 12, (*it)->_name.c_str(), temp );
				}
				if ( !(*it)->_enabled )
					buf << "{x";
			    f++;
			    if ( f == 5 ) {
					buf << "\n\r";
					f = 0;
				}
			}
		}
	}
	f = 0;
	if ( c->getLevel() >= BUILDER ) {
		buf << "\n\r\t{cbuilder (level " << BUILDER << ") commands:{x\n\r";
		for ( it = rCommandTable::Instance()._commands.begin(); it != rCommandTable::Instance()._commands.end(); ++it ) {
			if ( (*it)->_level == BUILDER ) {
				if ( !(*it)->_enabled )
					buf << "{w";
				if ( f == 0 ) {
					buf << "  " << (*it)->_name.c_str() << spaces( 12, (*it)->_name.c_str(), temp );
				} else {
					buf << (*it)->_name.c_str() << spaces( 12, (*it)->_name.c_str(), temp );
				}
				if ( !(*it)->_enabled )
					buf << "{x";
			    f++;
			    if ( f == 5 ) {
					buf << "\n\r";
					f = 0;
				}
			}
		}
	}
	f = 0;
	buf << "\n\r\t{c-- Commands --{x \n\r";
	for ( it = rCommandTable::Instance()._commands.begin(); it != rCommandTable::Instance()._commands.end(); ++it ) {
		if ( (*it)->_level == 1 ) {
				if ( !(*it)->_enabled )
					buf << "{w";
				if ( f == 0 ) {
					buf << "  " << (*it)->_name.c_str() << spaces( 12, (*it)->_name.c_str(), temp );
				} else {
					buf << (*it)->_name.c_str() << spaces( 12, (*it)->_name.c_str(), temp );
				}
				if ( !(*it)->_enabled )
					buf << "{x";
		    f++;
		    if ( f == 5 ) {
				buf << "\n\r";
				f = 0;
			}
		}
	}


	c->Send( buf );

	return true;
}

rCmdDescription::rCmdDescription() {
	SetName( "description" );
	SetLevel( BUILDER );
	SetEnabled( true );
	SetOmniset( false );
}

bool rCmdDescription::Execute( Character* c, const string& args ) {

	c->setVEdit( true );
	vEditList::Instance().act( c, args );

	return true;
}

rCmdDig::rCmdDig() {
	SetName( "dig" );
	SetLevel( BUILDER );
	SetEnabled( true );
	SetOmniset( false );
}

bool rCmdDig::Execute( Character* c, const string& args ) {
	std::string direction;
	std::string target;
	Room* to = 0;
	Room* from = 0;
	int vnum = 0;
	int dir = 0;
	int inverse = 0;

	split( args, direction, target );

	if ( direction.empty() || target.empty() ) {
		c->Send( " >> \"dig\" creates a two-way link from your current room to the target. If the target room does not already exist, dig will attempt to create the room automatically.\n\r\n\rsyntax: dig <direction> <vnum>\n\r" );
		return true;
	}

	dir = atoi( direction.c_str() );
	if ( direction == "north" || direction == "n" )
		dir = NORTH;
	else if ( direction == "east" || direction == "e" )
		dir = EAST;
	else if ( direction == "south" || direction == "s" )
		dir = SOUTH;
	else if ( direction == "west" || direction == "w" )
		dir = WEST;
	else if ( direction == "up" || direction == "u" )
		dir = UP;
	else if ( direction == "down" || direction == "d" )
		dir = DOWN;
	else {
		c->Send( "Invalid direction.\n\r" );
		return true;
	}

	inverse = Exit::Inverse( dir );
	vnum = atoi( target.c_str() );
	from = c->getRoom();

	rCmdMake make;

	std::string makeArgs;

	makeArgs << vnum;

	if ( !make.Execute( c, makeArgs ) ) {
		c->Send( "Room could not be created!\n\r" );
		return false;
	}

	if ( ( to = World::Instance().FindRoom( vnum ) ) == NULL ) {
		c->Send( "Error digging new room.\n\r" );
		return false;
	}

	from->GetExit( dir ).SetThere( true );
	from->GetExit( dir ).SetPoint( vnum );
	from->SetNoexit( false );
	to->GetExit( inverse ).SetThere( true );
	to->GetExit( inverse ).SetPoint( from->GetVnum() );
	to->SetNoexit( false );

	CmdGoto go;
	std::string goArgs;
	goArgs << to->GetVnum();
	go.Execute( c, goArgs );

	return true;
}

rCmdExit::rCmdExit() {
	SetName( "exit" );
	SetLevel( BUILDER );
	SetEnabled( true );
	SetOmniset( false );
}

bool rCmdExit::Execute( Character* c, const string& args ) {

	c->SetStatus( CONNECTED );
	c->Send( "You've been set to regular command mode.\n\r" );

	return true;
}

rCmdInfo::rCmdInfo() {
	SetName( "info" );
	SetLevel( BUILDER );
	SetEnabled( true );
	SetOmniset( false );
}

bool rCmdInfo::Execute( Character* c, const string& args ) {
	std::string buf;
	Room* room = 0;

	if ( args.empty() )
		room = c->getRoom();
	else {
		if ( ( room = World::Instance().FindRoom( atoi( args.c_str() ) ) ) == NULL ) {
			c->Send( "That room doesn't exist.\n\r" );
			return false;
		}
	}

	buf << "\t\t{!WRoom Information{x\n\r";
	buf << "Vnum: {C" << room->GetVnum() << "{x\n\r";
	buf << "Name: {C" << room->GetName() << "{x\n\r";
	buf << "Sector: {C" << Room::StringSector( room->GetSector() ) << "{x\n\r";
	buf << "Exits...\n\r";
	for ( int x=0; x < 6; x++ )
		if ( room->GetExit( x ).GetThere() )
			buf << '\t' << Exit::StringName( x ) << ": {C" << room->GetExit( x ).GetPoint() << "{x\n\r\n\r";
	buf << "Description...\n\r" << room->getDesc() << "\n\r";

	c->Send( buf );

	return true;
}

rCmdLink::rCmdLink() {
	SetName( "link" );
	SetLevel( BUILDER );
	SetEnabled( true );
	SetOmniset( false );
}

bool rCmdLink::Execute( Character* c, const string& args ) {
	std::string buf;
	std::string direction;
	std::string number;
	Room* to = 0;
	Room* from = 0;
	int dir = 0;

	if ( args.empty() ) {
		c->Send( " >> \"link\" creates a one way exit from your current room to the target.\n\r\n\rsyntax: link <direction> <vnum>\n\r" );
		return false;
	}

	split( args, direction, number );

	if ( direction == "north" || direction == "n" ) {
		dir = NORTH;
	}
	else if ( direction == "east" || direction == "e" ) {
		dir = EAST;
	}
	else if ( direction == "south" || direction == "s" ) {
		dir = SOUTH;
	}
	else if ( direction == "west" || direction == "w" ) {
		dir = WEST;
	}
	else if ( direction == "up" || direction == "u" ) {
		dir = UP;
	}
	else if ( direction == "down" || direction == "d" ) {
		dir = DOWN;
	}
	else {
		c->Send( "Invalid direction.\n\r" );
		return true;
	}

	if ( ( to = World::Instance().FindRoom( atoi( number.c_str() ) ) ) == NULL ) {
		c->Send( "Target room doesn't exist.\n\r" );
		return false;
	}
	from = c->getRoom();

	from->GetExit( dir ).SetThere( true );
	from->GetExit( dir ).SetPoint( to->GetVnum() );

	buf << "The " << Exit::StringName( dir ) << " exit was set/reset to " << to->GetVnum() << ".\n\r";
	from->SetNoexit( false );

	c->Send( buf );

	return true;
}

rCmdMake::rCmdMake() {
	SetName( "make" );
	SetLevel( BUILDER );
	SetEnabled( true );
	SetOmniset( false );
}

bool rCmdMake::Execute( Character* c, const string& args ) {
	int vnum = 0;
	bool valid = false;
	Room* room = 0;
	std::string buf;
	std::list< Area* >::iterator a_it;
	std::list< Room* >::iterator r_it;

	if ( args.empty() ) {
		c->Send( " >> \"make\" creates a room.\n\r\n\rsyntax: make <vnum>\n\r" );
		return false;
	}

	vnum = atoi( args.c_str() );

	if ( vnum < 50 ) {
		c->Send( "Invalid vnum.\n\r" );
		return false;
	}

	// Make sure vnum is in a valid area
	for ( a_it = World::Instance().getAreas().begin(); a_it != World::Instance().getAreas().end(); a_it++ ) {
		if ( vnum >= (*a_it)->GetFirstv() && vnum <= (*a_it)->GetLastv() ) {
			valid = true;
			// Make sure room doesn't exist
			for ( r_it = (*a_it)->getRooms().begin(); r_it != (*a_it)->getRooms().end(); r_it++ )
				if ( vnum == (*r_it)->GetVnum() ) {
					c->Send( "That room already exists.\n\r" );
					return false;
				}
			if ( valid ) {
				room = (*a_it)->addRoom();
				room->SetVnum( vnum );
				room->setArea( (*a_it) );
				buf << "Room " << vnum << " created successfully.\n\r";
				c->Send( buf );
				return true;
			}
		}
	}

	c->Send( "No area contains that vnum.\n\r" );
	return false;
}

rCmdName::rCmdName() {
	SetName( "name" );
	SetLevel( BUILDER );
	SetEnabled( true );
	SetOmniset( false );
}

bool rCmdName::Execute( Character* c, const string& args ) {
	std::string buf;

	if ( args.empty() ) {
		c->Send( " >> \"name\" changes the name of the current room.\n\r\n\rsyntax: name <name>\n\r" );
		return false;
	}

	c->getRoom()->SetName( args.c_str() );
	buf << "Room " << c->getRoom()->GetVnum() << "'s name changed to \"" << args << "\".\n\r";

	c->Send( buf );

	return true;
}

rCmdRemove::rCmdRemove() {
	SetName( "remove" );
	SetLevel( BUILDER );
	SetEnabled( true );
	SetOmniset( false );
}

bool rCmdRemove::Execute( Character* c, const string& args ) {
	std::string buf;
	int vnum;
	Area* area = 0;
	Room* room = 0;
	Exit* exit = 0;
	std::list< Area* >::iterator a_it;
	std::list< Room* >::iterator r_it;

	if ( args.empty() ) {
		c->Send( " >> \"remove\" deletes a room. All exits which point to the room will be automatically disabled.\n\r\n\rsyntax: remove <vnum>\n\r" );
		return false;
	}

	vnum = atoi( args.c_str() );

	if ( ( room = World::Instance().FindRoom( vnum ) ) == NULL ) {
		c->Send( "That room doesn't exist.\n\r" );
		return false;
	}

	for ( a_it = World::Instance().getAreas().begin(); a_it != World::Instance().getAreas().end(); a_it++ ) {
		for ( r_it = (*a_it)->getRooms().begin(); r_it != (*a_it)->getRooms().end(); r_it++ ) {
			for ( int z=0; z < 6; z++ ) {
				exit = &((*r_it)->GetExit( z ));
				if ( exit->GetPoint() == vnum ) {
					exit->SetPoint( 0 );
					exit->SetThere( 0 );
					bool noexits = true;
					for ( int i=0; i < 6; i++ ) {
						exit = &((*r_it)->GetExit( i ));
						if ( exit->GetThere() )
							noexits = false;
					}
					if ( noexits )
						(*r_it)->SetNoexit( true );
				}
			}
		}
	}

	area = room->getArea();
	area->getRooms().remove( room );
	delete room;
	room = 0;

	c->Send( "Room deleted.\n\r" );

	return true;
}

rCmdReset::rCmdReset() {
	SetName( "reset" );
	SetLevel( BUILDER );
	SetEnabled( true );
	SetOmniset( false );
}

bool rCmdReset::Execute( Character* c, const string& args ) {
	std::string buf;
	std::string tmp;
	std::string type;
	std::string vnum;
	std::string number;
	std::string limit;
	Area* area = c->getRoom()->getArea();
	Room* room = c->getRoom();
	Reset* reset = 0;
	int i = 0;

	if ( args.empty() ) {
		buf << "{WReset{x   {ctype{x   {Mvnum{x   {Bnumber{x   {glimit{x\n\r";
		buf << "----------------------------------------------\n\r";
		for ( std::list< Reset* >::iterator it = area->getResets().begin(); it != area->getResets().end(); it++, i++ )
			if ( (*it)->getVnum() == room->GetVnum() ) {
				buf << format( 5, i, tmp, 'W' ) << "   {c" << (*it)->charType() << "   {x   ";
				buf << format( 4, (*it)->getTarget(), tmp, 'M' ) << "   ";
				buf << format( 6, (*it)->getNumber(), tmp, 'B' ) << "   ";
				buf << format( 5, (*it)->getLimit(), tmp, 'g' ) << "\n\r";
			}
	} else {
		split( args, type, vnum, number, limit );
		if ( type == "-" ) {
			i = 0;
			for ( std::list< Reset* >::iterator it = area->getResets().begin(); it != area->getResets().end(); it++, i++ )
				if ( i == atoi( vnum.c_str() ) ) {
					area->getResets().remove( *it );
					break;
				}
			buf << "Reset " << atoi( vnum.c_str() ) << " removed.\n\r";
		} else {
			area->getResets().push_back( reset = new Reset );
			reset->setVnum( c->getRoom()->GetVnum() );
			if ( type == "o" || type == "O" )
				reset->setType( OBJECT );
			else
				reset->setType( MOB );
			reset->setTarget( atoi( vnum.c_str() ) );
			reset->setNumber( atoi( number.c_str() ) );
			reset->setLimit( atoi( limit.c_str() ) );
		}
	}

	c->Send( buf );

	return true;
}

rCmdRlist::rCmdRlist() {
	SetName( "rlist" );
	SetLevel( BUILDER );
	SetEnabled( true );
	SetOmniset( false );
}

bool rCmdRlist::Execute( Character* c, const string& args ) {
	std::string buf;
	std::string tmp;
	std::string search = args;
	Area* area = c->getRoom()->getArea();
	std::list< Room* >::iterator r_it;

	if ( search.empty() ) {
		for ( r_it = area->getRooms().begin(); r_it != area->getRooms().end(); r_it++ )
			buf << " [ " << format( 5, (*r_it)->GetVnum(), tmp, 'g' ) << " ]  {G" << (*r_it)->GetName() << "{x\n\r";
	} else {
		for ( r_it = area->getRooms().begin(); r_it != area->getRooms().end(); r_it++ )
			if ( (*r_it)->GetName() == search || sub_str( search, to_str((*r_it)->GetName()) ) )
				buf << " [ " << format( 5, (*r_it)->GetVnum(), tmp, 'g' ) << " ]  {G" << (*r_it)->GetName() << "{x\n\r";
	}

	c->Send( buf );

	return true;
}

rCmdSector::rCmdSector() {
	SetName( "sector" );
	SetLevel( BUILDER );
	SetEnabled( true );
	SetOmniset( false );
}

bool rCmdSector::Execute( Character* c, const string& args ) {
	std::string buf;

	if ( args.empty() ) {
		c->Send( " >> \"sector\" changes the sector of the current room.\n\r\n\rsyntax: sector <number>\n\r" );
		return false;
	}

	c->getRoom()->SetSector( atoi( args.c_str() ) );
	buf << "Room " << c->getRoom()->GetVnum() << "'s sector changed to \"" << Room::StringSector( atoi( args.c_str() ) ) << "\".\n\r";

	c->Send( buf );

	return true;
}

rCmdUnlink::rCmdUnlink() {
	SetName( "unlink" );
	SetLevel( BUILDER );
	SetEnabled( true );
	SetOmniset( false );
}

bool rCmdUnlink::Execute( Character* c, const string& args ) {
	std::string buf;
	std::string direction;
	int dir = 0;

	if ( args.empty() ) {
		c->Send( " >> \"unlink\" removes an exit from the current room. (Reciprocal exits are unaffected.)\n\r\n\rsyntax: unlink <direction>\n\r" );
		return false;
	}

	split( args, direction );

	if ( direction == "north" || direction == "n" ) {
		dir = NORTH;
	}
	else if ( direction == "east" || direction == "e" ) {
		dir = EAST;
	}
	else if ( direction == "south" || direction == "s" ) {
		dir = SOUTH;
	}
	else if ( direction == "west" || direction == "w" ) {
		dir = WEST;
	}
	else if ( direction == "up" || direction == "u" ) {
		dir = UP;
	}
	else if ( direction == "down" || direction == "d" ) {
		dir = DOWN;
	}
	else {
		c->Send( "Invalid direction.\n\r" );
		return false;
	}

	c->getRoom()->GetExit( dir ).SetThere( false );
	c->getRoom()->GetExit( dir ).SetPoint( 0 );

	c->getRoom()->SetNoexit( true );

	for ( int i=0; i < 6; i++ )
		if ( c->getRoom()->GetExit( i ).GetThere() )
			c->getRoom()->SetNoexit( false );

	buf << "The " << Exit::StringName( dir ) << " exit was unlinked.\n\r";

	c->Send( buf );

	return true;
}
